"use client"
import WebrtcNav from "@/components/WebrtcNav";
import React, { useRef, useState } from "react";

const WebRTCExample: React.FC = () => {
  const localVideoRef = useRef<HTMLVideoElement | null>(null);
  const remoteVideoRef = useRef<HTMLVideoElement | null>(null);

  const localPeerConnection = useRef<RTCPeerConnection | null>(null);
  const remotePeerConnection = useRef<RTCPeerConnection | null>(null);
  const localStreamRef = useRef<MediaStream | null>(null);

  const [callDisabled, setCallDisabled] = useState(true);
  const [hangupDisabled, setHangupDisabled] = useState(true);

  const mediaStreamConstraints: MediaStreamConstraints = { video: true, audio: true };
  const offerOptions: RTCOfferOptions = { offerToReceiveVideo: true };
  const trace = (text: string) => {
    const now = (window.performance.now() / 1000).toFixed(3);
    console.log(now, text.trim());
  };

  const gotLocalMediaStream = (mediaStream: MediaStream) => {
    if (localVideoRef.current) {
      localVideoRef.current.srcObject = mediaStream;
    }
    localStreamRef.current = mediaStream;
    trace("Received local stream.");
    setCallDisabled(false);
  };

  const handleLocalMediaStreamError = (error: Error) => {
    trace(`navigator.getUserMedia error: ${error.toString()}.`);
  };

const gotRemoteMediaStream = (event: RTCTrackEvent) => {
  if (remoteVideoRef.current) {
    remoteVideoRef.current.srcObject = event.streams[0];
  }
  trace("Remote peer connection received remote stream.");
};
  const handleConnection = (event: RTCPeerConnectionIceEvent) => {
    const peerConnection = event.target as RTCPeerConnection;
    const iceCandidate = event.candidate;

    if (iceCandidate) {
      const newIceCandidate = new RTCIceCandidate(iceCandidate);
      const otherPeer =
        peerConnection === localPeerConnection.current
          ? remotePeerConnection.current
          : localPeerConnection.current;

      otherPeer
        ?.addIceCandidate(newIceCandidate)
        .then(() => trace(`${getPeerName(peerConnection)} addIceCandidate success.`))
        .catch((error) =>
          trace(`${getPeerName(peerConnection)} failed to add ICE Candidate:\n${error.toString()}.`)
        );

      trace(
        `${getPeerName(peerConnection)} ICE candidate:\n${event.candidate.candidate}.`
      );
    }
  };

  const handleConnectionChange = (event: Event) => {
    const pc = event.target as RTCPeerConnection;
    trace(`${getPeerName(pc)} ICE state: ${pc.iceConnectionState}.`);
  };

  const setSessionDescriptionError = (error: Error) => {
    trace(`Failed to create session description: ${error.toString()}.`);
  };

  const setDescriptionSuccess = (peerConnection: RTCPeerConnection, functionName: string) => {
    trace(`${getPeerName(peerConnection)} ${functionName} complete.`);
  };

  const setLocalDescriptionSuccess = (peerConnection: RTCPeerConnection) => {
    setDescriptionSuccess(peerConnection, "setLocalDescription");
  };

  const setRemoteDescriptionSuccess = (peerConnection: RTCPeerConnection) => {
    setDescriptionSuccess(peerConnection, "setRemoteDescription");
  };

  const createdOffer = (description: RTCSessionDescriptionInit) => {
    trace(`Offer from localPeerConnection:\n${description.sdp}`);

    localPeerConnection.current
      ?.setLocalDescription(description)
      .then(() => setLocalDescriptionSuccess(localPeerConnection.current!))
      .catch(setSessionDescriptionError);

    remotePeerConnection.current
      ?.setRemoteDescription(description)
      .then(() => setRemoteDescriptionSuccess(remotePeerConnection.current!))
      .catch(setSessionDescriptionError);

    remotePeerConnection.current
      ?.createAnswer()
      .then(createdAnswer)
      .catch(setSessionDescriptionError);
  };

  const createdAnswer = (description: RTCSessionDescriptionInit) => {
    trace(`Answer from remotePeerConnection:\n${description.sdp}.`);

    remotePeerConnection.current
      ?.setLocalDescription(description)
      .then(() => setLocalDescriptionSuccess(remotePeerConnection.current!))
      .catch(setSessionDescriptionError);

    localPeerConnection.current
      ?.setRemoteDescription(description)
      .then(() => setRemoteDescriptionSuccess(localPeerConnection.current!))
      .catch(setSessionDescriptionError);
  };

  const startAction = () => {
    navigator.mediaDevices
      .getUserMedia(mediaStreamConstraints)
      .then(gotLocalMediaStream)
      .catch(handleLocalMediaStreamError);
    trace("Requesting local stream.");
  };

  const callAction = () => {
    setCallDisabled(true);
    setHangupDisabled(false);

    trace("Starting call.");

    const videoTracks = localStreamRef.current?.getVideoTracks() || [];
    const audioTracks = localStreamRef.current?.getAudioTracks() || [];

    if (videoTracks.length > 0) trace(`Using video device: ${videoTracks[0].label}.`);
    if (audioTracks.length > 0) trace(`Using audio device: ${audioTracks[0].label}.`);

    const servers: RTCConfiguration | null = null;

    localPeerConnection.current = new RTCPeerConnection(servers || undefined);
    localPeerConnection.current.addEventListener("icecandidate", handleConnection);
    localPeerConnection.current.addEventListener("iceconnectionstatechange", handleConnectionChange);

    remotePeerConnection.current = new RTCPeerConnection(servers || undefined);
    remotePeerConnection.current.addEventListener("icecandidate", handleConnection);
    remotePeerConnection.current.addEventListener("iceconnectionstatechange", handleConnectionChange);
    remotePeerConnection.current.addEventListener("track", gotRemoteMediaStream);

    if (localStreamRef.current) {
        const videoTracks = localStreamRef.current.getVideoTracks();
        const audioTracks = localStreamRef.current.getAudioTracks();

        if (videoTracks.length > 0) {
            localPeerConnection.current.addTrack(videoTracks[0], localStreamRef.current);
        }
        if (audioTracks.length > 0) {
            localPeerConnection.current.addTrack(audioTracks[0], localStreamRef.current);
        }
}

    localPeerConnection.current
      .createOffer(offerOptions)
      .then(createdOffer)
      .catch(setSessionDescriptionError);
  };

  const hangupAction = () => {
    localPeerConnection.current?.close();
    remotePeerConnection.current?.close();
    localPeerConnection.current = null;
    remotePeerConnection.current = null;
    setHangupDisabled(true);
    setCallDisabled(false);
    trace("Ending call.");
  };

  const getPeerName = (peerConnection: RTCPeerConnection) =>
    peerConnection === localPeerConnection.current
      ? "localPeerConnection"
      : "remotePeerConnection";

  return (
    <div>
      <WebrtcNav text={'简单连接'}></WebrtcNav>
      <div className="flex space-x-4 my-2 shadow-lg py-2">
        <video className="border-1 rouded-sm" ref={localVideoRef} autoPlay playsInline muted />
        <video className="border-1 rouded-sm" ref={remoteVideoRef} autoPlay playsInline />
      </div>
      <div className="flex space-x-4 my-2">
        <button onClick={startAction}  className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-800">Start</button>
        <button onClick={callAction} disabled={callDisabled} className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-800">
          Call
        </button>
        <button onClick={hangupAction} disabled={hangupDisabled} className="rounded bg-red-500 px-4 py-2 text-white hover:bg-red-800">
          Hang Up
        </button>
      </div>
    </div>
  );
};

export default WebRTCExample;
